#!/bin/bash -e
#
#   Neutron3529's Unity Game Plugin
#   Copyright (C) 2022 Neutron3529
#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU Affero General Public License as
#   published by the Free Software Foundation, either version 3 of the
#   License, or (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU Affero General Public License for more details.
#
#   You should have received a copy of the GNU Affero General Public License
#   along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
############################################################################
#
#   * compile instructions: put this file and `utils.cs` in `steamapps`
#   * folder, open a terminal in the same folder, and execute:
#   *
#   * ```
#   *     chmod +x ${file}.cs
#   *     ./${file}.cs
#   * ```
#   *
#   * then the mod will be compiled automatically.
#   *
#   * Here we wrote a shebang like file, which is correct
#   * in my computer (Manjaro XFCE), if such script do not work
#   * in your computer, you could just try the instructions below :

export GAME_NAME="Software Inc"                             # might modify if the name mismatch.
export GAME_DIR="$GAME_NAME"                                # might be modified, but "$GAME_NAME" cover most of the cases.

export FILE_NAME="$0"
export ASSEMBLY="Assembly-CSharp"                           # might be modified
export UTILS="utils.cs"                                     # might be modified if you do not put utils.cs in the current dir.
export PLUGIN_ID="Neutron3529.Cheat"                        # should be modified
export NAMESPACE_ID="Neutron3529.Cheat"                     # should be modified
export GAME_BASE_DIR="common/$GAME_DIR"                     # should modify GAME_DIR instead since GAME_DIR == GAME_NAME is almost always true.

export IFS=$'\n' # to disable the annoying space.
export DOTNET="dotnet" # the location of the DOTNET executable file.
[ -z "$DOTNET_CSC_DLL" ] && export DOTNET_CSC_DLL=`\ls /usr/share/dotnet/sdk/*/Roslyn/bincore/csc.dll` # In manjaro, the csc.dll is located in /usr/share/dotnet/sdk/*/Roslyn/bincore/csc.dll

__MODE_VERBOSE=99 # is the line number of "#define VERBOSE", may be modified
__MODE_DEBUG__=$((__MODE_VERBOSE+1))
__MODE_RELEASE=$((__MODE_DEBUG__+1))

case $1 in
    V)       _MODE__SELECT_=$__MODE_VERBOSE     ;;
    v)       _MODE__SELECT_=$__MODE_VERBOSE     ;;
    VERBOSE) _MODE__SELECT_=$__MODE_VERBOSE     ;;
    verbose) _MODE__SELECT_=$__MODE_VERBOSE     ;;
    D)       _MODE__SELECT_=$__MODE_DEBUG__     ;;
    d)       _MODE__SELECT_=$__MODE_DEBUG__     ;;
    DEBUG)   _MODE__SELECT_=$__MODE_DEBUG__     ;;
    debug)   _MODE__SELECT_=$__MODE_DEBUG__     ;;
    *)       _MODE__SELECT_=$__MODE_RELEASE     ;;
esac

( yes "" | head -n $_MODE__SELECT_ | head -n-1  ; tail $FILE_NAME -n+$_MODE__SELECT_ ; cat $UTILS) | sed s/%%NAMESPACE_ID%%/${NAMESPACE_ID}/g | sed s/%%PLUGIN_ID%%/${PLUGIN_ID}/g | $DOTNET $DOTNET_CSC_DLL -nologo -t:library \
  -r:"${GAME_BASE_DIR}/BepInEx/core/BepInEx.dll" \
  -r:"${GAME_BASE_DIR}/BepInEx/core/0Harmony.dll" \
  -r:"${GAME_BASE_DIR}/BepInEx/core/BepInEx.Harmony.dll" \
  `[ -e "${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/netstandard.dll" ] && echo "-r:\"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/netstandard.dll\""` \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/System.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/System.Core.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/UnityEngine.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/UnityEngine.AIModule.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/UnityEngine.CoreModule.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/UnityEngine.UI.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/mscorlib.dll" \
  $(for i in "${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/$ASSEMBLY"*.dll ; do echo -e "-r:\"$i\"\n" ; done) \
  -out:"${GAME_BASE_DIR}/BepInEx/plugins/${FILE_NAME%.*}".dll \
  -optimize `[ "$_MODE__SELECT_" == "$__MODE_DEBUG__" ] && echo -debug` \
  - && rm -f "${GAME_BASE_DIR}/BepInEx/config/${PLUGIN_ID}.cfg";

if [ -n "$2" ]; then
    git add ${FILE_NAME}
    case $2 in
        R) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
        r) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
        RANDOM) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
        random) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
        U) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
        u) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
        UPLOAD) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
        upload) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
        *) git commit -am "$2" ;;
    esac
    git push
fi
exit

#define VERBOSE // the line of __MODE_VERBOSE
#define DEBUG



using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;

using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;

namespace %%NAMESPACE_ID%%
{
    [BepInPlugin("%%PLUGIN_ID%%", "%%NAMESPACE_ID%%", "0.1.0")]
    public partial class Cheat : BaseUnityPlugin {
        void Start2() {
            // 主要逻辑放在`utils.cs`中，这里的start2只是为了以防万一
            // 目前来说，这个函数的唯一用途是用来“叮”……
            // 就像这样：
            logger("叮~修改器启动，请安心游戏");
        }
        [Desc("超级员工")]
        class SuperEmployee : Bbool {
            [HarmonyPostfix, HarmonyPatch(typeof(Actor), "GetStateInfluence")]
            public static void Postfix1(ref Actor __instance, ref float __result) {
                __result=1f;// 这个变量会影响员工头上冒字符的速度，因此不能太大
            }
            [HarmonyPostfix, HarmonyPatch(typeof(Actor), "GetPCAddonBonus")]
            public static void Postfix2(ref Actor __instance, ref float __result) {
                __result=10000f;
            }
            [HarmonyPatch(typeof(Furniture), "GetMaxEffectivenessValue")]
            public static bool Prefix(ref float __result) {
                __result=10000f;
                return false;
            }
        }

        [Desc("超级电脑")]
        class FurnitureComputerPowerGetterPatch : Bbool { // 会更改电脑售价，因此不单独使用
            [HarmonyPrefix, HarmonyPatch(typeof(Furniture), "ComputerPower", MethodType.Getter)]
            public static bool Prefix1(ref float __result) {
                __result=10000f;
                return false;
            }
            [HarmonyPrefix, HarmonyPatch(typeof(Furniture), "GetCost", new Type[] { typeof(string), typeof(float), typeof(int), typeof(float), typeof(bool)} )]
            public static bool Prefix2(ref float __result) {
                __result=0f;
                return false;
            }
        }

        [Desc("最大化bug修复数量")]
        class SoftwareAlphaMaxBugFixPatch : Bbool {
            [HarmonyPrefix, HarmonyPatch(typeof(SoftwareAlpha), "MaxBugFix")]
            public static bool Prefix1(ref float __result, SoftwareAlpha __instance) {
                __result=__instance.Bugs;
                return false;
            }
            [HarmonyPrefix, HarmonyPatch(typeof(SoftwareProduct), "Update")]
            public static void Prefix2(ref int bugsAdded) {
                bugsAdded=0;
            }
        }


        [Desc("迅速补充专家经验")]
        [HarmonyPatch(typeof(Employee), "AddSpecExperience")]
        class EmployeeAddSpecExperiencePatch : Bbool {
            public static bool Prefix(ref float value) {
                value=1f;
                return true;
            }
        }

        [Desc("特长点数恒定为最大值")]
        [HarmonyPatch(typeof(GameSettings), "GetMaxSpecPoints")]
        class GameSettingsGetMaxSpecPointsPatch : Bbool {
            public static bool Prefix(ref int __result, Employee.EmployeeRole role) {
                switch (role) {
                case Employee.EmployeeRole.Lead:
                    __result=Employee.LeadSpecs.Length * 3;
                    return false;
                case Employee.EmployeeRole.Programmer:
                    __result=GameSettings.Instance.CodeSpecializations.Length * 3;
                    return false;
                case Employee.EmployeeRole.Designer:
                    __result=GameSettings.Instance.Specializations.Length * 3;
                    return false;
                case Employee.EmployeeRole.Artist:
                    __result=GameSettings.Instance.ArtSpecializations.Length * 3;
                    return false;
                case Employee.EmployeeRole.Service:
                    __result=Employee.ServiceSpecs.Length * 3;
                    return false;
                default:
                    return true;
                }
            }
        }

        [Desc("雇员培训瞬间完成")]
        [HarmonyPatch(typeof(EducationWindow), "SendEmployee")]
        class EducationWindowSendEmployeePatch : Bbool {
            public static bool Prefix(ref Actor emp,Employee.EmployeeRole role, string spec) {
                emp.Courses.Add(new KeyValuePair<Employee.EmployeeRole, string>(role, spec));
                emp.LastCourse = SDateTime.Now();
                return false;
            }
        }

        [Desc("实体分销占比")]
        [HarmonyPatch(typeof(MarketSimulation), "GetPhysicalVsDigital")]
        class MarketSimulationGetPhysicalVsDigitalPatch : Bfloat {
            public static float val;public void Init() {base.Init(ref val);}
            public static bool Prefix(ref float __result) {
                __result=val;
                return false;
            }
        }
        [Desc("物品永不损毁")]
        class UpgradableDegradePatch : Bbool {
            static IEnumerable<MethodBase> TargetMethods() {
                yield return typeof(Upgradable).GetMethod("Degrade",(BindingFlags)(-1));
                yield return typeof(Upgradable).GetMethod("DegradeMonths",(BindingFlags)(-1));
            }
            public static bool Prefix(ref Upgradable __instance) {
                __instance.Quality=1f;
                return false;
            }
        }

        [Desc("员工义务劳动")]
        [HarmonyPatch(typeof(Employee), "ChangeSalary")]
        class EmployeeChangeSalaryPatch : Bbool {
            public static bool Prefix(ref Employee __instance, ref float newSalary,ref float askedFor) {
                __instance.Salary=0f;
                __instance.AskedFor=0f;
                __instance.Demanded=0f;
                newSalary=0f;
                askedFor=0f;
                return true;
            }
        }

        [Desc("员工永不疲劳")]
        [HarmonyPatch(typeof(Actor), "Fatigue")]
        class ActorFatiguePatch : Bbool {
            public static void Postfix(ref Actor __instance) {
                __instance.employee.Demanded=-__instance.employee.Worth(-1,false)-10000f;
                __instance.employee.Salary=0f;
                __instance.employee.AskedFor=0f;
                foreach(Employee.ThoughtEffect x in (from x in __instance.employee.Thoughts.List where x.Mood.Negative select x)){
                    __instance.employee.Thoughts.Remove(x.Mood.Thought);
                }
            }
        }

        [Desc("员工心情拉满")]
        [HarmonyPatch(typeof(Employee), "UpdateMood")]
        class EmployeeUpdateMoodPatch : Bbool {
            public static void Postfix(ref Employee __instance) {
                __instance.Hunger = 1f;
                __instance.Energy = 1f;
                __instance.Bladder = 1f;
                __instance.Social = 1f;
                __instance.Stress = 1f;
                __instance.Posture = 1f;
                __instance.JobSatisfaction=2f;
                foreach(Employee.ThoughtEffect x in (from x in __instance.Thoughts.List where x.Mood.Negative select x)){
                    __instance.Thoughts.Remove(x.Mood.Thought);
                }
            }
        }
        [Desc("员工灵感恒定为最大值")]
        [HarmonyPatch(typeof(Employee), "TakeInspiration")]
        class EmployeeTakeInspirationPatch : Bbool {
            public static void Postfix(ref Employee __instance) {
                __instance.Inspiration=2f;
            }
        }
        [Desc("恒定生产最具灵感的作品")]
        [HarmonyPatch(typeof(Employee), "GetWeightedLeadSpecFactor")]
        class EmployeeGetWeightedLeadSpecFactorPatch : Bbool {
            public static float Postfix(float result) {
                return 100f;
            }
        }
    }
}

